#ifndef __BB_EXCEPTION_H__
#define __BB_EXCEPTION_H__

#include <stdexcept>
#include <string>
#include <string_view>

#include "util/macro/str_cat.h"

namespace bb::exception {
class BehaviorBaseException : public std::exception {
  public:
    BehaviorBaseException(std::string_view message) : message_(static_cast<std::string>(message)) {}

    template <typename... SV>
    BehaviorBaseException(const SV&... args) : message_(StrCat(args...)) {}

    const char* what() const noexcept { return message_.c_str(); }

  private:
    std::string message_;
};

// This errors are usually related to problems which "probably" require code refactoring
// to be fixed.
class BugError : public BehaviorBaseException {
  public:
    BugError(std::string_view message) : BehaviorBaseException(message) {}

    template <typename... SV>
    BugError(const SV&... args) : BehaviorBaseException(args...) {}
};

// This errors are usually related to problems which "probably" require code refactoring
// to be fixed.
class LogicError : public BehaviorBaseException {
  public:
    LogicError(std::string_view message) : BehaviorBaseException(message) {}

    template <typename... SV>
    LogicError(const SV&... args) : BehaviorBaseException(args...) {}
};

// This errors are usually related to problems that are related to data or conditions
// that happen only at run-time
class RuntimeError : public BehaviorBaseException {
  public:
    RuntimeError(std::string_view message) : BehaviorBaseException(message) {}

    template <typename... SV>
    RuntimeError(const SV&... args) : BehaviorBaseException(args...) {}
};

} // namespace bb::exception

#endif // __BB_EXCEPTION_H__
